var projection = null;
var date = new Date();
var timestamp = null;
var infoPopup = false;
var circle = null;

function drawMap(mapJSON,locationJSON,streamJSON,lon,lat,x,y,scale,globeIndicator,monthIndicator,startTimestamp) {
	var margin = {top: 0, right: 0, bottom: 0, left: 0},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
	
	
	if(startTimestamp != undefined)
		timestamp = startTimestamp;
	
	if (globeIndicator==true) {
		circle = d3.geo.greatCircle().origin([lon, lat]);
		projection 	= d3.geo.azimuthal().scale(scale).origin([lon,lat]).mode("orthographic");
	}
		
	else
		projection 	= d3.geo.mercator().scale(1743).translate([x,y]);
	
    path = d3.geo.path().projection(projection);
	
	var zoom = d3.behavior.zoom()
	    .translate(projection.translate())
	    .scale(projection.scale())
	    .scaleExtent([height, 160 * height])
	    .on("zoom", move);
	
	var svg = d3.select("#map").append("svg")
	    .attr("width", width + margin.left + margin.right)
	    .attr("height", height + margin.top + margin.bottom)
	    .append("g")
	    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
	    .call(zoom);
	
	svg.append("rect")
	    .attr("class", "frame")
	    .attr("width", width)
	    .attr("height", height);
	
	var g = svg.append("g")
				.attr("id","states");

	var mousedown = false;
	
	d3.json(mapJSON, function(collection) {
		states = g.selectAll(".map")
		  		.data(collection.features)
		  		.enter().append("path")
		  		.attr("class", "map")
//		  		.attr("d", path)
		  		.attr("title", function(o){
				  return o.properties.name;
				})
				.on("mouseover", function() { 
					if(!mousedown)
						$(this).attr("class","state_selected");
				}) 
				.on("mouseout", function() { 
					$(this).attr("class","map");

				})
				.on("mousedown", function() {
					$(this).attr("class","map");
					mousedown = true;
				})
				.on("mouseup", function() {
					mousedown = false;
				})
			;
		if(globeIndicator)
			states.attr("d", function(d) { return path(circle.clip(d)); })
		else
			states.attr("d", path);
	});
	

	
	plotDataStreams(streamJSON,svg,projection,timestamp);
	plotLocations(locationJSON,svg,projection,timestamp);	

	var lvOld0 = 0, lvOld1 = 0;
	function move() {
	  if (globeIndicator==true) {
	  	  if (lvOld0!=0 && lvOld1!=0) {
	  	  	  lon = lon - (d3.event.translate[0]-lvOld0) / 10;
	  	  	  lat = lat - 0 + (d3.event.translate[1]-lvOld1) / 10;
	  	  	  circle = d3.geo.greatCircle().origin([lon, lat]);
	  	  	  projection.origin([lon,lat]).scale(d3.event.scale);
	  	  	  states.attr("d", function(d) { return path(circle.clip(d)); })
	  	  }
	  	  lvOld0 = d3.event.translate[0]-0;
	  	  lvOld1 = d3.event.translate[1]-0;
	  } else {
		projection.translate(d3.event.translate).scale(d3.event.scale);
		states.attr("d", path);
	  }
	  
	  scaleSlider.slider("value",d3.event.scale);
	  plotDataStreams(streamJSON,svg,projection,timestamp);
	  plotLocations(locationJSON,svg,projection,timestamp);
	}
	
	return {
		svg : svg,
		scale : function(value){
		  	projection.translate(projection.translate()).scale(value);			  		
			states.attr("d", path);
			plotDataStreams(streamJSON,svg,projection,timestamp);
			plotLocations(locationJSON,svg,projection,timestamp);
		},
		move: function(direction,cords) {
			switch (direction) {
				case "x":
					projection.translate([projection.translate()[0]+cords,projection.translate()[1]]).scale(projection.scale());
					break;
				case "y":
					projection.translate([projection.translate()[0],projection.translate()[1]+cords]).scale(projection.scale());
					break;
				case "xy":
				  	projection.translate(cords).scale(1743);			  		
					break;	
			}
			states.attr("d", path);
			plotDataStreams(streamJSON,svg,projection,timestamp);
			plotLocations(locationJSON,svg,projection,timestamp);
		}
	};
}

function plotLocations(json, svg, projection,p_timestamp){
	 $("circle").remove();
	 $("#locations").remove();
	
	svg.append("g")
	.attr("id", "locations");
	 
	var length = 0;
	if($(json).size() == 0)
		length = 1;
	else
		length = $(json).size();
	
	for(i = 0; i < length; i++) {
		var jsonData = null;
		if(length == 1)
			jsonData = json;
		else
			jsonData = json[i];
		
		var arr = new Object();
		arr["type"] = "LocationsCollection";
		arr["dataGroupCount"] = 6;
		arr["data"] = [];
		
		var fct = function(jsonData,i,callback) {
			d3.json(jsonData, function(json) {
				callback(json,i);
			})
		}
		
		fct(jsonData,i,function(json,cnt) {
			json.data.forEach(function(o) {
		        if(o.properties.timestamp == p_timestamp)
		        	arr["data"].push(o);
			});	
			
			var arrValues = [];
			var arrRange = [];
			var arrMax = [];
			
			arr.data.forEach(function(o) {
				arrValues.push(o.properties.value)
			});	
			
			var avg= getAverage(arrValues)
			var dbl_sd = 2*getStandardDeviation(arrValues);
			
			for(j = 0; j < arrValues.length; j++) {
				if(arrValues[j] < (avg+dbl_sd))
					arrRange.push(arrValues[j]);
				else
					arrMax.push(arrValues[j]);
			}
			
			var sum = 0;
			var max = 0;
			
			for(j = 0; j < arrRange.length; j++) {
				if(max < arrRange[j])
					max = arrRange[j];
				sum += arrRange[j];
			}
			
			var borders = [];
			var borderStep = max / arr.dataGroupCount;
			for(j = 0; j < arr.dataGroupCount; j++) {
				if(borderStep != 0)
					borders.push(borderStep*(j+1));
			}

			svg.select("#locations")
				.selectAll("circle")
				.data(arr.data)
				.enter().append("circle")
				.attr("r", function(o){return getRadius(borders,max,arr.dataGroupCount,o)})
				.attr("transform", function(d) {
					if(globeIndicator){
						var clipped = circle.clip(d); 
						if (clipped) 
							return "translate(" + projection(clipped.geometry.coordinates) + ")"; 
						else {
							$(this).attr("r",0);
							return false;
						}	
					}
					else
						return "translate(" + projection(d.geometry.coordinates) + ")";
					})
				
				.attr("class","location")
				.attr("class", "location")		
				.attr("fill",getColor(cnt))
				.on("mouseover", function(o){
					$(".infoPopup").remove();
					if($('.infoPopup').length == 0) {
						drawLocationPopup(o,d3.event);
						$(".infoPopup").fadeIn();
					} 
				 })
				.on("mouseout", function(){
						setTimeout(function(){ 
							var popupToClose = $(".infoPopup");
							if(infoPopup == false) {
								popupToClose.fadeOut('normal'); 
							}	
						}, 500);						
					})
			     ;			
		});
	}

	
	function getRadius(borders,max,dataGroupCount,o){
		if(borders.length != 0){
			for(j = 0; j < borders.length; j++) {
				if (o.properties.value <= borders[j]) {
					switch (j) {
						case 0:
							return 4;
						case (borders.length-1):
							return 12;
						default:
							var stepSize = 8/dataGroupCount;
							var x = 4+stepSize*(j+1);
							return x;
					}
				}
			}
			return 12;
		} else
			return 9;
	}	
}

function plotDataStreams(json, svg, projection,p_timestamp){
	if(json != null) {
		$("#streams").remove();
		
		var arcs = svg.append("g").attr("id", "streams");
		var path = d3.geo.path().projection(projection);
		
		var arr = new Object();
		arr["type"] = "DatastreamCollection";
		arr["dataGroupCount"] = 6;
		arr["data"] = [];
		
		d3.json(json, function(collection) {
			collection.data.forEach(function(o) {
		        if(o.properties.timestamp == p_timestamp && o.properties.attribute[1][1] == kpi)
		        	arr["data"].push(o);
			});	
			
			var arrValues = [];
			var arrRange = [];
			var arrMax = [];
			
			arr.data.forEach(function(o) {
				var value = 0;
				arrValues.push(o.properties.value[1]);
			});	
			
			var avg= getAverage(arrValues)
			var dbl_sd = 2*getStandardDeviation(arrValues);
			
			for(j = 0; j < arrValues.length; j++) {
				if(arrValues[j] < (avg+dbl_sd))
					arrRange.push(arrValues[j]);
				else
					arrMax.push(arrValues[j]);
			}
			
			var sum = 0;
			var max = 0;
			
			for(j = 0; j < arrRange.length; j++) {
				if(max < arrRange[j])
					max = arrRange[j];
				sum += arrRange[j];
			}
			
			var borders = [];
			var borderStep = max / arr.dataGroupCount;
			for(j = 0; j < arr.dataGroupCount; j++) {
				if(borderStep != 0)
					borders.push(borderStep*(j+1));
			}
			
			  var links = [];
			  
			  arr.data.forEach(function(o,index) {
			        links.push({
			          source: o.geometry.coordinates[0],
			          target: o.geometry.coordinates[1],
			          sender: o.properties.sender,
			          recipient: o.properties.recipient,
			          attribute: o.properties.attribute[1],
			          value: arrValues[index],
			          amount: o.properties.value
			        });
			  });	
		  
			arcs.selectAll("path")
				.data(links)
				.enter().append("path")
				.attr("stroke-width", function(o){return getStrokeWidth(borders,max,arr.dataGroupCount,o)+"px"})
				.on("mouseover", function(o){
					$(".infoPopup").remove();
					if($('.infoPopup').length == 0) {
						drawStreamPopup(o,d3.event);
						$(".infoPopup").fadeIn();
					} 
				 })
				.on("mouseout", function(){
						setTimeout(function(){ 
							var popupToClose2 = $(".infoPopup");
							if(infoPopup == false) {
								popupToClose2.fadeOut('normal'); 
							}	
						}, 500);						
					})
				.attr("d", function(d) { 
					if(globeIndicator) {
						var tmpSource = {"type":"Point","coordinates":d.source};
						var tmpTarget = {"type":"Point","coordinates":d.target};
						var sourceClip = circle.clip(tmpSource); 
						var targetClip = circle.clip(tmpTarget);
						
						if(sourceClip != false && targetClip != false){
							var source = projection(d.source);
							var target = projection(d.target);
							var dx = target[0] - source[0], 
								dy = target[1] - source[1], 
								dr = Math.sqrt(dx * dx + dy * dy); 
							return "M" + source[0] + "," + source[1] + "A" + dr + "," + dr + " 0 0,1 " + target[0] + "," + target[1]; 
						}
					} else {
						var source = projection(d.source);
						var target = projection(d.target);
						var dx = target[0] - source[0], 
							dy = target[1] - source[1], 
							dr = Math.sqrt(dx * dx + dy * dy); 
						return "M" + source[0] + "," + source[1] + "A" + dr + "," + dr + " 0 0,1 " + target[0] + "," + target[1]; 
					}

					
				})
				; 	  
		});
	}
	
	function getStrokeWidth(borders,max,dataGroupCount,o){
		if(borders.length != 0){
			for(j = 0; j < borders.length; j++) {
				if (o.value <= borders[j]) {
					switch (j) {
						case 0:
							return 1;
						case (borders.length-1):
							return 3;
						default:
							var stepSize = 3/dataGroupCount;
							var x = stepSize*(j+1);
							return x;
					}
				}
			}
			return 3;
		} else
			return 9;
	}	
}


function drawLocationPopup(o,event){
	var data = null;
	
	if(o["properties"] != undefined)
		data = o["properties"];
	else if(o["data"] != undefined)
		data = o["data"];
	
	var container = $(document.createElement('div')).attr({
		"class" : "infoPopup"
	}).css("border-color",$(event.target).css("fill"));
	
	$(container).hover(function(){
		infoPopup = true;
	}, function(){
		$(this).fadeOut("normal");
		infoPopup = false;
	});
	
	var top = $(event.target).offset().top - 60;
	if(top < 0) top = 0;
	var left = $(event.target).offset().left + 25;
	
	$(container).css({
		"top": top,
		"left": left
	});
	
	var title = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(data.name);
	
	var dataValue = "";
	
	if(data.value != "")
		dataValue = ": "+numToStr(data.value);
	
	var value = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(capitaliseFirstLetter(data.attribute)+dataValue).css({
		"text-align": "center"
	});
	
	var seperator = $(document.createElement('div')).attr({
		"class" : "infoPopupSeperator"
	});
	
	$(container).append(title);
	$(container).append(value);
	$(container).append(seperator);
	$("body").append(container);
}

function drawStreamPopup(o,event){
	var data = null;
	
	var container = $(document.createElement('div')).attr({
		"class" : "infoPopup"
	}).css("border-color","#ccc");
	
	$(container).hover(function(){
		infoPopup = true;
	}, function(){
		$(this).fadeOut("normal");
		infoPopup = false;
	});
	
	var top = event.pageY - 60;
	if(top < 0) top = 0;
	var left = event.pageX + 25;
	
	$(container).css({
		"top": top,
		"left": left
	});
	
	var title = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html("Foreign Exchange");
	
	
	var value = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(o.attribute[1]).css({
		"text-align": "center"
	});
	
	var seperator = $(document.createElement('div')).attr({
		"class" : "infoPopupSeperator"
	});
	
	$(container).append(title);
	$(container).append(value);
	$(container).append(seperator);
	
	var stream = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(o.sender+" - "+o.recipient);
	
	
	var value = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(numToStr(o.amount[0]) +" "+o.attribute[0]).css({
		"text-align": "center"
	});
	
	$(container).append(stream);
	$(container).append(value);
	
	var stream = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(o.recipient+" - "+o.sender);
	
	
	var value = $(document.createElement('div')).attr({
		"class" : "infoPopupTitle"
	}).html(numToStr(o.amount[1]) +" "+o.attribute[1]).css({
		"text-align": "center"
	});
	
	$(container).append(stream);
	$(container).append(value);
	
	$("body").append(container);
}